#include "AbstractManager.h"
#include "AbstractMappingWindow.h"
#include "xMappingTree.h"
#include "NodeItem.h"
#include "LineItem.h"
#include "NodeInPort.h"
#include "NodeOutPort.h"
#include "DiagramScene.h"
#include "xNodeType_Math.h"
#include "MappingNodeHandler.h"
#include "MappingEngine.h"
#include "MDSParser.h"
#include "xMappingNode.h"
#include "mappingdialog.h"
#include "MathNodeItem.h"

#include <QtCore/QFile>
#include <QtCore/QTextStream>


AbstractManager::AbstractManager( AbstractMappingWindow* dialog ):
QObject(),
xmt_( new xMappingTree ),
dialog_( dialog ),
inputPanel_( nullptr ),
outputPanel_( nullptr ),
nodeList_()
{
}

AbstractManager::~AbstractManager()
{

}

NodeItem* AbstractManager::createNode( std::string name )
{
	NodeItem* node = nullptr;
	if( name == "math" ) {
		node = new MathNodeItem( name, this->xmt_, this );
	} else {
		node = new NodeItem( name, this->xmt_, this);
	}
	connect(node, SIGNAL(itemSelected(NodeItem* )), this, SIGNAL(itemSelected(NodeItem*)));
	connect(node, SIGNAL(portListChanged(NodeItem* )), this, SIGNAL(itemSelected(NodeItem*)));
	connect(node, SIGNAL(itemDeSelected()), this, SIGNAL(itemDeSelected()));
	this->nodeList_.push_back(node);
	return node;
}

NodeItem* AbstractManager::createNode( xMappingNode* mappingNode )
{
	NodeItem * node = nullptr;
	if( mappingNode->getNodeTypePtr()->getType() == "math" ) {
		node = new MathNodeItem( mappingNode, this);
	} else {
		node = new NodeItem( mappingNode, this);
	}
	connect(node, SIGNAL(itemSelected(NodeItem* )), this, SIGNAL(itemSelected(NodeItem*)));
	connect(node, SIGNAL(portListChanged(NodeItem* )), this, SIGNAL(itemSelected(NodeItem*)));
	connect(node, SIGNAL(itemDeSelected()), this, SIGNAL(itemDeSelected()));
	this->nodeList_.push_back(node);
	return node;
}

LineItem* AbstractManager::createLine( NodeInPort* inport, NodeOutPort* outport)
{
	LineItem* line = new LineItem( this->xmt_, inport, outport, this);
	return line;
}

void AbstractManager::deleteLine( LineItem* line)
{
	this->xmt_->delete_link( line->getLink());	// 從xMappingTree裡面將link移除
}

void AbstractManager::deleteNode( NodeItem* node)
{
	// 刪除連接node的link
	removeAllLinks(node);

	this->dialog_->currentScene()->removeItem(node);

	auto it = remove( this->nodeList_.begin(), this->nodeList_.end(), node );
	this->nodeList_.erase( it, this->nodeList_.end() );

	this->xmt_->delete_node(node->getMappingNode());	//從xMappingTree裡面將Node移除

	delete node;
}

// 在pos位置上面是否有port(pos是scene position)，如果沒有則回傳NULL
NodePort* AbstractManager::getCollidePort( QPointF pos)
{
	for ( int i = 0; i < this->nodeList_.size(); ++i )
	{
		AbstractShapeItem* node = this->nodeList_.at(i);
		vector<NodeInPort*> inportList = node->getInportList();
		for ( int j = 0; j < inportList.size(); ++j )
		{
			QPointF itemPos = inportList.at(j)->mapFromScene(pos);
			if (inportList.at(j)->contains(itemPos) ) {
				return inportList.at(j);
			}
			if (inportList.at(j)->getParent()->getName() == "terminal") {
				inportList.at(j)->setBrush(QBrush(Qt::white));
			} else {
				inportList.at(j)->setBrush(QBrush("#333333"));
			}
		}

		vector<NodeOutPort*> outportList = node->getOutportList();
		for ( int j = 0; j < outportList.size(); ++j )
		{
			QPointF itemPos = outportList.at(j)->mapFromScene(pos);
			if (outportList.at(j)->contains(itemPos) ) {
				return outportList.at(j);
			}
			outportList.at(j)->setPen(QPen(QBrush(Qt::white), 3));
		}
	}
	return NULL;
}

// 驗證link是否合法，只簡單檢查幾個項目
bool AbstractManager::verifyLink( NodePort* pressPort, NodePort* releasePort)
{
	// 如果是同一個node port相連接，則不合法
	if ( pressPort->parentItem() == releasePort->parentItem() )
		return false;

	// 只有當是一個inport、一個outport且不為同一個node時才是合法的link
	if ( pressPort->getPortIOType() == NodePort::INPORT && releasePort->getPortIOType() == NodePort::OUTPORT ) {
		if ( pressPort->getPortLineList().size() == 0 ) {
			return true;
		}
	}
	else if( pressPort->getPortIOType() == NodePort::OUTPORT && releasePort->getPortIOType() == NodePort::INPORT) {
		if ( releasePort->getPortLineList().size() == 0 ) {
			return true;
		}
	}
	else
		return false;

	return false;
}

xMappingTree* AbstractManager::getMappingTree()
{
	return this->xmt_;
}

AbstractMappingWindow* AbstractManager::getMappingDialog()
{
	return this->dialog_;
}

// 檢查所有 math mapping node 是否都有被設定運算式
bool AbstractManager::validateAllNodes() const {
	for( auto it = this->nodeList_.begin(); it != this->nodeList_.end(); ++it ) {
		if( ( *it )->nodeType() == AbstractShapeItem::MAPPING_NODE ) {
			auto item = dynamic_cast< NodeItem * >( *it );
			assert( item || !"dynamic_cast failed" );
			if( !item->validate() ) {
				return false;
			}
		}
	}
	return true;
}


// 將某個des檔案從compositeVMS.des中移除
void AbstractManager::removeVMfromCompositeDes( QString vmName, bool isDelete )
{
	const QString DES_FILE_PATH = "DES\\";

	QFile file( DES_FILE_PATH + "CompositeVMs.des");
	QFile tempFile( DES_FILE_PATH + "~TempCompositeVMs.des");
	QString path;

	if ( file.open(QIODevice::ReadOnly) && tempFile.open(QIODevice::WriteOnly)) {
		QTextStream stream(&file);
		QTextStream tempStream(&tempFile);
		QString line;

		// assert DES 表頭
		line = stream.readLine();
		assert(line == "#DES version 2.2");
		tempStream << line << "\r\n";
		line = stream.readLine();
		assert(line == "SECTION vm_descriptors {");
		tempStream << line << "\r\n";

		line = stream.readLine();
		while ( line != "}" ){
			QStringList token = line.split(" ");

			// 比對vm名稱，如果不同就寫進temp file
			if ( token.at(2) != vmName ){
				tempStream << line << "\r\n";
			} else {
				path = token.at(5);
			}
			line = stream.readLine();
		}
		tempStream << "}";
		file.close();
		tempFile.close();
	} else {
		assert(false);
	}

	file.remove();
	tempFile.rename( DES_FILE_PATH + "CompositeVMs.des");

	// 假如使用者是點選 delete，把檔案刪除
	if ( isDelete ) {
		QFile file(path);
		assert(file.exists());
		file.remove();
	}
	MappingNodeHandler::getInstance()->deleteVMFromLibrary(vmName.toStdString());
}

bool AbstractManager::isInForEachRect( AbstractShapeItem* item )
{
	MappingDialog *dialog = dynamic_cast<MappingDialog*>( this->dialog_ );

	if ( dialog != NULL && dialog->getForeachRect() != NULL ){
		return item->collidesWithItem(dialog->getForeachRect() ,Qt::ContainsItemShape);
	}

	return false;
}

void AbstractManager::deletePanelItem(PanelItem*)
{

}

AbstractPanel* AbstractManager::getInputPanel()
{
	return this->inputPanel_;
}

void AbstractManager::removeAllLinks( AbstractShapeItem* node )
{
	for ( int i = 0; i < node->getInportList().size(); ++i) {
		node->getInportList().at(i)->removeAllLinks();
	}

	for ( int i = 0; i < node->getOutportList().size(); ++i) {
		node->getOutportList().at(i)->removeAllLinks();
	}
}

std::vector<AbstractShapeItem*>& AbstractManager::getNodeList()
{
	return this->nodeList_;
}

//由mds檔來建立xmt
xMappingTree* AbstractManager::createXMTFromMDS( QString fileName, WOP_Entry* currentEntry )
{
	pair<string,string> mdsPair=MappingEngine::getInstance()->readMDSfile(fileName.toStdString());
	string mds = mdsPair.second;
	MDSParser *parser = new MDSParser();
	xMappingTree* mappingTree = parser->fromMDStoXMappingTree(QString(mds.c_str()), currentEntry);
	//xMappingTree* mappingTree=xMappingTree::fromMDStoXMappingTree(mds,currentEntry);

	delete parser;
	parser = NULL;
	return mappingTree;

}
